#ifndef COMMON_H
#define COMMON_H

#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>

#ifdef __cplusplus
extern "C"
{
#endif

typedef int8_t s8;
typedef int8_t i8;
typedef uint8_t u8;

typedef int16_t s16;
typedef int16_t i16;
typedef uint16_t u16;

typedef int32_t s32;
typedef int32_t i32;
typedef uint32_t u32;

typedef int64_t s64;
typedef int64_t i64;
typedef uint64_t u64;

enum cipher_mode_t {
	cipher_mode_ecb = 0,
	cipher_mode_cbc = 1,
	cipher_mode_ctr = 2
};

typedef enum cipher_mode_t cipher_mode_t;

void generate_random_iv(u8 *iv, int length);

void *copy(void *dst, const void *src, size_t size);

void crash(const char *file, int line, const char *function, const char *message);

#define crash_here(message) crash(__FILE__, __LINE__, __FUNCTION__, message)

#ifdef _COMMON_CRYPTO

#define __u32 u32
#define __le32 u32
#define __be32 u32
#define __u64 u64
#define __le64 u64
#define __be64 u64

#define swab32(x) ((__u32)(				\
	(((__u32)(x) & (__u32)0x000000ffUL) << 24) |		\
	(((__u32)(x) & (__u32)0x0000ff00UL) <<  8) |		\
	(((__u32)(x) & (__u32)0x00ff0000UL) >>  8) |		\
	(((__u32)(x) & (__u32)0xff000000UL) >> 24)))

#define swab64(x) ((__u64)(                         \
	(((__u64)(x) & (__u64)0x00000000000000ffULL) << 56) |   \
	(((__u64)(x) & (__u64)0x000000000000ff00ULL) << 40) |   \
	(((__u64)(x) & (__u64)0x0000000000ff0000ULL) << 24) |   \
	(((__u64)(x) & (__u64)0x00000000ff000000ULL) <<  8) |   \
	(((__u64)(x) & (__u64)0x000000ff00000000ULL) >>  8) |   \
	(((__u64)(x) & (__u64)0x0000ff0000000000ULL) >> 24) |   \
	(((__u64)(x) & (__u64)0x00ff000000000000ULL) >> 40) |   \
	(((__u64)(x) & (__u64)0xff00000000000000ULL) >> 56)))

#define le32_to_cpu(x) (x)
#define cpu_to_le32(x) (x)
#define cpu_to_be32(x) ((__be32)swab32((x)))
#define be32_to_cpu(x) swab32((__u32)(__be32)(x))
#define le64_to_cpu(x) (x)
#define cpu_to_le64(x) (x)
#define cpu_to_be64(x) ((__be64)swab64((x)))
#define be64_to_cpu(x) swab64((__u64)(__be64)(x))

typedef struct {
	u64 a, b;
} u128;

typedef struct {
	u64 a, b;
} be128;

typedef struct {
	u64 b, a;
} le128;

static inline void le128_to_be128(be128 *dst, const le128 *src)
{
	dst->a = cpu_to_be64(le64_to_cpu(src->a));
	dst->b = cpu_to_be64(le64_to_cpu(src->b));
}

static inline void be128_to_le128(le128 *dst, const be128 *src)
{
	dst->a = cpu_to_le64(be64_to_cpu(src->a));
	dst->b = cpu_to_le64(be64_to_cpu(src->b));
}

static inline void le128_inc(le128 *i)
{
	u64 a = le64_to_cpu(i->a);
	u64 b = le64_to_cpu(i->b);

	b++;
	if (!b)
		a++;

	i->a = cpu_to_le64(a);
	i->b = cpu_to_le64(b);
}

static inline void u128_xor(u128 *r, const u128 *p, const u128 *q)
{
	r->a = p->a ^ q->a;
	r->b = p->b ^ q->b;
}

static inline void be128_xor(be128 *r, const be128 *p, const be128 *q)
{
	u128_xor((u128 *)r, (u128 *)p, (u128 *)q);
}

static inline void le128_xor(le128 *r, const le128 *p, const le128 *q)
{
	u128_xor((u128 *)r, (u128 *)p, (u128 *)q);
}

static inline __u32 rol32(__u32 word, unsigned int shift)
{
	return (word << shift) | (word >> (32 - shift));
}

static inline __u32 ror32(__u32 word, unsigned int shift)
{
	return (word >> shift) | (word << (32 - shift));
}

static inline void crypto_xor_byte(u8 *a, const u8 *b, i64 size)
{
	for (; size; size--)
		*a++ ^= *b++;
}

static inline void crypto_xor(u8 *dst, const u8 *src, i64 size)
{
	u32 *a = (u32 *)dst;
	u32 *b = (u32 *)src;

	for (; size >= 4; size -= 4)
		*a++ ^= *b++;

	crypto_xor_byte((u8 *)a, (u8 *)b, size);
}

#endif

#ifdef __cplusplus
}
#endif

#endif // COMMON_H
